package dao

import (
	"context"
	"database/sql"
	"errors"
	"forum/internal/common"
	"forum/internal/domain"
	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"time"
)

type UserDao interface {
	Insert(ctx context.Context, user domain.User) error
	FindByEmail(ctx context.Context, user domain.User) (domain.User, error)
	FindById(ctx context.Context, id int64) (domain.User, error)
}

type UserMysqlDao struct {
	db *gorm.DB
}

func NewUserMysqlDao(db *gorm.DB) *UserMysqlDao {
	return &UserMysqlDao{db: db}
}

func (u *UserMysqlDao) Insert(ctx context.Context, user domain.User) error {
	dao := u.EntityToDao(user)
	now := time.Now().UnixMilli()
	var mysqlErr *mysql.MySQLError
	dao.Ctime = now
	dao.Utime = now
	err := u.db.WithContext(ctx).Create(&dao).Error
	if errors.As(err, &mysqlErr) {
		const uniqueConflictsErrNo uint16 = 1062
		if mysqlErr.Number == uniqueConflictsErrNo {
			//唯一索引邮箱冲突
			return common.ErrRepeatEmail
		}
	}
	return err
}

func (u *UserMysqlDao) FindByEmail(ctx context.Context, user domain.User) (domain.User, error) {
	var userDao User
	err := u.db.WithContext(ctx).Where("email=?", user.Email).First(&userDao).Error
	return u.DaoToEntity(userDao), err
}

func (u *UserMysqlDao) FindById(ctx context.Context, id int64) (domain.User, error) {
	var userDao User
	err := u.db.WithContext(ctx).Where("id=?", id).First(&userDao).Error
	return u.DaoToEntity(userDao), err
}

func (u *UserMysqlDao) DaoToEntity(user User) domain.User {
	return domain.User{
		Id:       user.Id,
		Name:     user.Name,
		Email:    user.Email.String,
		Password: user.Password,
	}
}
func (u *UserMysqlDao) EntityToDao(user domain.User) User {
	return User{
		Id:   user.Id,
		Name: user.Name,
		Email: sql.NullString{
			String: user.Email,
			Valid:  user.Email != "",
		},
		Password: user.Password,
	}
}

type User struct {
	Id       int64          `gorm:"primaryKey,autoIncrement"`
	Name     string         `gorm:"type=varchar(128)"`
	Email    sql.NullString `gorm:"unique"`
	Password string
	Ctime    int64
	Utime    int64
}
